#include "main.h"

//The camera
SDL_Rect camera = { 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT };

//Sprite from the tile sheet
SDL_Rect clips[ TILE_SPRITES ];

//The surfaces
SDL_Surface *player = NULL;
SDL_Surface *screen = NULL;
SDL_Surface *tileSheet = NULL;

SDL_Surface *greenGear = NULL;
SDL_Surface *redGear = NULL;

SDL_Surface *enemy = NULL;

SDL_Surface *ready = NULL;

//Player sprite from character sprite sheet
SDL_Rect clipsRight[ PLAYER_ANIMATIONS ];
SDL_Rect clipsLeft[ PLAYER_ANIMATIONS ];
SDL_Rect clipsUp[ PLAYER_ANIMATIONS ];
SDL_Rect clipsDown[ PLAYER_ANIMATIONS ];

//The event structure
SDL_Event event;

/// Loads the image with the given filename
SDL_Surface *load_image( std::string filename )
{
    //The image that's loaded
    SDL_Surface* loadedImage = NULL;

    //The optimized surface that will be used
    SDL_Surface* optimizedImage = NULL;

    //Load the image
    loadedImage = IMG_Load( filename.c_str() );

    //If the image loaded
    if( loadedImage != NULL )
    {
        //Create an optimized surface
        optimizedImage = SDL_DisplayFormatAlpha( loadedImage );

        //Free the old surface
        SDL_FreeSurface( loadedImage );

        //If the surface was optimized
        if( optimizedImage != NULL )
        {
            //Color key surface
            SDL_SetColorKey( optimizedImage, SDL_RLEACCEL | SDL_SRCCOLORKEY, optimizedImage->format->colorkey);
            //SDL_SetColorKey( optimizedImage, SDL_RLEACCEL | SDL_SRCCOLORKEY, SDL_MapRGBA( optimizedImage->format, 0, 0xFF, 0xFF, 0x00 ) );
            //SDL_SetAlpha(optimizedImage, SDL_SRCALPHA, 100);
           //;
        }
    }

    //Return the optimized surface
    return optimizedImage;
}

//draws the given source file on the screen
void apply_surface( int x, int y, SDL_Surface* source, SDL_Surface* destination, SDL_Rect* clip = NULL, bool adjustAlpha = 0 )
{
    //Holds offsets
    SDL_Rect offset;

    //Get offsets
    offset.x = x;
    offset.y = y;
    
    
    //Blit
    if (adjustAlpha)
    {
       source->format->Amask = 0;
    }
    SDL_BlitSurface( source, clip, destination, &offset );
    
    //std::cout << "adhafkljaf";
}

bool check_collision( SDL_Rect A, SDL_Rect B )
{
    //The sides of the rectangles
    int leftA, leftB;
    int rightA, rightB;
    int topA, topB;
    int bottomA, bottomB;

    //Calculate the sides of rect A
    leftA = A.x;
    rightA = A.x + A.w;
    topA = A.y;
    bottomA = A.y + A.h;

    //Calculate the sides of rect B
    leftB = B.x;
    rightB = B.x + B.w;
    topB = B.y;
    bottomB = B.y + B.h;

    //If any of the sides from A are outside of B
    if( bottomA <= topB )
    {
        return false;
    }

    if( topA >= bottomB )
    {
        return false;
    }

    if( rightA <= leftB )
    {
        return false;
    }

    if( leftA >= rightB )
    {
        return false;
    }

    //If none of the sides from A are outside B
    return true;
}

bool init()
{
    //Initialize all SDL subsystems
    if( SDL_Init( SDL_INIT_EVERYTHING ) == -1 )
    {
        return false;
    }

    //Set up the screen
    screen = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_SWSURFACE );

    //If there was an error in setting up the screen
    if( screen == NULL )
    {
        return false;
    }


    //Set the window caption
    SDL_WM_SetCaption( "THE GAME!", NULL );

    //If everything initialized fine
    return true;
}

bool load_files()
{
    //Load the player image
    player = load_image( "Lucas.png" );

    //If there was a problem in loading the player
    if( player == NULL )
    {
        return false;
    }

    //Load the tile sheet
    tileSheet = load_image( "forestTile.png" );//( "tiles.png" );

    //If there was a problem in loading the tiles
    if( tileSheet == NULL )
    {
        return false;
    }
    
    //Load the enemy image
    enemy = load_image( "enemy.png" );//( "tiles.png" );

    //If there was a problem in loading the tiles
    if( enemy == NULL )
    {
        return false;
    }
    
    greenGear = load_image( "gear_green.png" );
    if( greenGear == NULL )
    {
        return false;
    }
    
    redGear = load_image( "gear_red.png" );
    if( redGear == NULL )
    {
        return false;
    }
    
    ready = load_image( "ball.png" );
    if ( ready == NULL )
    {
         return false;
    }
    
    //If everything loaded fine
    return true;
}

void clean_up( Tile *tiles[] )
{
    //Free the surfaces
    SDL_FreeSurface( player );
    SDL_FreeSurface( tileSheet );

    SDL_FreeSurface( enemy );
    
    SDL_FreeSurface( greenGear );
    SDL_FreeSurface( redGear );
    
    SDL_FreeSurface( ready );
    
    //Free the tiles
    for( int t = 0; t < TOTAL_TILES; t++ )
    {
        delete tiles[ t ];
    }

    //Quit SDL
    SDL_Quit();
}

void clip_tiles()
{
    int j, k;
    int i = 0;
    const int MULTIPLIER = 32;
    
    while ( i < TILE_SPRITES )
    {
        for (j = 0; j < TILESHEET_WIDTH / TILE_WIDTH; ++j)
        {
            for (k = 0; k < TILESHEET_HEIGHT / TILE_HEIGHT; ++k)
            {
                clips[i].x = j * MULTIPLIER;
                clips[i].y = k * MULTIPLIER;
                clips[i].w = TILE_WIDTH;
                clips[i++].h = TILE_HEIGHT;
            }
        }
    }
}

void set_char_sprite_clips()
{
    int i = 0, j, k;
    
    while ( i < PLAYER_ANIMATIONS )
    {
          for (j = 0; j < CHARSHEET_HEIGHT / PLAYER_HEIGHT; ++j)
          {
              for (k = 0; k < CHARSHEET_WIDTH / PLAYER_WIDTH; ++k)
              {
                  switch (j)
                  {
                         case 0:
                              clipsDown[i].x = k * PLAYER_WIDTH;
                              clipsDown[i].y = j * PLAYER_HEIGHT;
                              clipsDown[i].w = PLAYER_WIDTH;
                              clipsDown[i++].h = PLAYER_HEIGHT;
                              break;
                         case 1:
                              clipsLeft[i].x = k * PLAYER_WIDTH;
                              clipsLeft[i].y = j * PLAYER_HEIGHT;
                              clipsLeft[i].w = PLAYER_WIDTH;
                              clipsLeft[i++].h = PLAYER_HEIGHT;
                              break;
                         case 2:
                              clipsRight[i].x = k * PLAYER_WIDTH;
                              clipsRight[i].y = j * PLAYER_HEIGHT;
                              clipsRight[i].w = PLAYER_WIDTH;
                              clipsRight[i++].h = PLAYER_HEIGHT;
                              break;
                         case 3:
                              clipsUp[i].x = k * PLAYER_WIDTH;
                              clipsUp[i].y = j * PLAYER_HEIGHT;
                              clipsUp[i].w = PLAYER_WIDTH;
                              clipsUp[i++].h = PLAYER_HEIGHT;
                              break;
                  }
              }
              if (j + 1 < CHARSHEET_HEIGHT / PLAYER_HEIGHT)
                 i = 0;
          }
    }
}

int main( int argc, char* args[] )
{
    //Quit flag
    bool quit = false;

    //The player
    Player myPlayer;

    //The tiles that will be used
    Tile *tiles[ TOTAL_TILES ];

    //Enemy
    Enemy theEnemy;

    //The frame rate regulator
    Timer fps;
    
    //Level counter
    Timer counter;
    
    //Gear indicators
    Gear red(false);
    Gear green(true);

    //Ready/pause screen
    Ready ball;
    
    //Initialize
    if( init() == false )
    {
        return 1;
    }

    //Load the files
    if( load_files() == false )
    {
        return 1;
    }

    //Clip the tile sheet
    clip_tiles();
    
    //Clip the character tile sheet
    set_char_sprite_clips();

    //Set the tiles
    if( set_tiles( tiles ) == false )
    {
        return 1;
    }

    Tile *t = tiles[index_of_tile(3,3)];
    cout << index_of_tile(3,3) << " " << t->get_type() << "\n";
    
    //pause loop
    while ( SDL_WaitEvent( &event ) )
    {
        if ( event.key.keysym.sym == SDLK_RETURN )
        {
           std::cout << "BEGIN!" << "\n";
           break;
        }        
    }
    
    //start timer
    counter.start();
    
    //While the user hasn't quit
    while( quit == false && green.getCurrentAlpha() != SDL_ALPHA_TRANSPARENT )
    {
        //Start the frame timer
        fps.start();
        
        //While there's events to handle
        while( SDL_PollEvent( &event ) )
        {
            //Handle events for the player
            myPlayer.handle_input();

            //If the user has Xed out the window
            if( event.type == SDL_QUIT )
            {
                //Quit the program
                quit = true;
            }
        }
        
        if ( check_collision(myPlayer.getBox(), ball.getBox()) )
        {
           ball.setVisible(false);
           quit = true;
        }
        
        //update green gear alpha
        green.updateAlpha( (counter.get_ticks() / 1000), 30, check_collision( myPlayer.getBox(), theEnemy.getBox() ) );
           
        //Move the player
        myPlayer.move( tiles );
        
        //theEnemy.find_path( tiles, 0, 0);
        theEnemy.move( tiles );

        //Set the camera
        myPlayer.set_camera();
        
        //Show the tiles
        for( int t = 0; t < TOTAL_TILES; t++ )
        {
            tiles[ t ]->show();
        }

        //Show the player on the screen
        myPlayer.show();

        //Show the enemy on the screen
        theEnemy.show();
        
        red.show();
        green.show();
        
        ball.show();
        
        //Update the screen
        if( SDL_Flip( screen ) == -1 )
        {
            return 1;
        }

        //Cap the frame rate
        if( fps.get_ticks() < 1000 / FRAMES_PER_SECOND )
        {
            SDL_Delay( ( 1000 / FRAMES_PER_SECOND ) - fps.get_ticks() );
        }
    }
    
    int remTime = counter.get_ticks() / 1000;
    counter.stop();
    
    //pause loop
    while ( SDL_WaitEvent( &event ) )
    {
        if ( event.key.keysym.sym == SDLK_RETURN )
        {
           std::cout << "END! Time stopped: " << remTime << "\n";
           break;
        }        
    }  

    //Clean up
    clean_up( tiles );

    return 0;
}
